/**
 * 
 */
package org.tuestudent.grouppa;

import org.json.JSONArray;
import org.json.JSONObject;
import org.tuestudent.grouppa.AppContext.ActiveScreens;
import org.tuestudent.grouppa.LoginViewController.LoginResponse;

/**
 * @author s121170 Class to provide services to group views
 */
public class GroupViewController extends ViewController {

    /**
     * hidden constructor, use getInstance()
     */
    private GroupViewController() {

    }

    private static GroupViewController instance;

    public static GroupViewController getInstance() {
        if (instance != null)
            return instance;

        instance = new GroupViewController();
        return instance;
    }

    /**
     * changes active group for a user
     * 
     * @param groupName
     *            name of the group to change to
     * @throws Exception
     *             if the user doesn't belong to this group
     */
    public void makeActiveGroup(String groupName) throws Exception {
        // TODO: send request to change active group for a user
        Main.getContext().setCurrentGroup(groupName,true);
    }

    /**
     * calls the server to create a new group
     * 
     * @param groupName
     *            name of the group to create
     * @param password
     *            password for the group
     */
    public void createGroup(String groupName, String password) {
        // CHECK: send request to create a new group
        MessageFromApp message = new MessageFromApp();
        String username = Main.getContext().currentUserName;
        message.from = username;
        message.messageType = "createGroupResponse";
        message.task = "createGroup";
        message.toController = "Group";
        message.toGroup = "";
        message.serializedArguments =
                "{\"groupName\":\"" + groupName + "\",\"password\":\""
                        + password + "\",\"userName\":\"" + username + "\"}";
        Main.getConnection().sendMessage(message);
    }

    /**
     * Sends request to change the pin of the group
     * @param groupName
     * @param newPin
     */
    public void changeGroupPin(String groupName,String newPin)
    {
        MessageFromApp message = new MessageFromApp();
        String username = Main.getContext().currentUserName;
        message.from = username;
        message.messageType = "changeGroupPinResponse";
        message.task = "changeGroupData";
        message.toController = "Group";
        message.toGroup = groupName;
        message.serializedArguments =
                "{\"groupName\":\"" + groupName + "\",\"newPin\":\""
                        + newPin + "\"}";
        Main.getConnection().sendMessage(message);
    }
    /**
     * calls the server to get list of members of a group
     * 
     * @param groupName
     *            name of the group to create
     */
    public void getGroupMembers(String groupName) {
        // CHECK: send request to create a new group
        MessageFromApp message = new MessageFromApp();
        String username = Main.getContext().currentUserName;
        message.from = username;
        message.messageType = "getGroupMembersResponse";
        message.task = "getAllMembers";
        message.toController = "Group";
        message.toGroup = "";
        message.serializedArguments =
                "{\"groupName\":\"" + groupName + "\"}";
        Main.getConnection().sendMessage(message);
    }

    /**
     * contains response to group creation
     */
    public class CreateGroupResponse {

        public boolean created;
        public boolean joined;
        public String errorReason;
        public String groupName;
        /**
         * is the user now a manager of newly created group?
         */
        public boolean manager;
        public String pin;
    }

    /**
     * for listing of group members
     *
     */
    public class GroupMember {
        public GroupMember(String name, boolean isManager) {
            this.name = name;
            this.isManager = isManager;
        }
        public String name;
        public boolean isManager;
    }
    /**
     * makes the user to quit a group
     * 
     * @param groupName
     *            a group for which user wants to quit
     */
    public void leaveGroup(String groupName) {
        // TODO: send request to quit from a group to server
    }


    @Override
    public void onMessageReceived(MessageFromServer message) {
        // CHECK: handle messages

        AppContext ctx = Main.getContext();
        if (ctx.activeScreen != ActiveScreens.grouppaScreen
                || checkForError(message))
            return; // ignoring messages if grouppa screen is not active
        if (message.messageType.equals("createGroupResponse")) {
            processCreateGroupResponse(message, ctx);
        } else if (message.messageType.equals("joinGroupResponse")) {
            processJoinGroupResponse(message, ctx);
        } else if (message.messageType.equals("getGroupMembersResponse")) {
            processGetGroupMembersResponse(message,ctx);
        } else if (message.messageType.equals("changeGroupPinResponse")) {
            processChangeGroupPinResponse(message,ctx);
        }

    }

    private void processJoinGroupResponse(MessageFromServer message,
            AppContext ctx) {
        JoinGroupResponse response = new JoinGroupResponse();
        try {
            JSONObject args = new JSONObject(message.serializedArguments);
            response.joined = args.optBoolean("joined");
            response.errorReason = args.optString("reason");
            response.groupName = args.getString("groupName");
            response.pin = args.getString("pin");
            if (response.joined) {
                ctx.addJoinedGroup(response.groupName,response.pin);
            }
            MyGroups.getInstance().onJoinGroupResponse(response);
        } catch (Exception ex) {
            ctx.grouppaActivity.errorPopup("Error: " + ex.getMessage());
        }
    }
    
    private void processGetGroupMembersResponse(MessageFromServer message,
            AppContext ctx) {
        if(!(ctx.currentGrouppaFragment instanceof GroupInfo))
        {
            return;
        }
        GroupInfo groupInfoFragment = (GroupInfo)ctx.currentGrouppaFragment;
        GetAllMembersResponse response = new GetAllMembersResponse();
        try {
            JSONObject args = new JSONObject(message.serializedArguments);
            response.groupName = args.getString("groupName");
            
            JSONArray members = args.getJSONArray("members");
            GroupMember [] membersArray = new GroupMember[members.length()];
            for(int i =0; i < members.length();i++)
            {
                JSONObject jmember = members.getJSONObject(i);
                membersArray[i] = new GroupMember(jmember.getString("userName"),jmember.getBoolean("isManager"));
            }
            response.members = membersArray;
            groupInfoFragment.onGetGroupMembersResponse(response);
        } catch (Exception ex) {
            ctx.grouppaActivity.errorPopup("Error: " + ex.getMessage());
        }
    }

    private void processCreateGroupResponse(MessageFromServer message,
            AppContext ctx) {
        CreateGroupResponse response = new CreateGroupResponse();
        try {
            JSONObject args = new JSONObject(message.serializedArguments);
            response.created = args.getBoolean("created");
            response.joined = args.getBoolean("joined");
            response.groupName = args.optString("groupName");
            response.manager = args.getBoolean("manager");
            response.errorReason = args.optString("reason");
            response.pin = args.getString("pin");
            if (response.joined) {
                ctx.addJoinedGroup(response.groupName,response.pin);
                ctx.joinedGroups.get(response.groupName).isManager = response.manager;
            }
            ctx.grouppaActivity.onCreateGroupResponse(response);
        } catch (Exception ex) {
            ctx.grouppaActivity.errorPopup("Error: " + ex.getMessage());
        }
    }

    public void joinGroup(String groupName, String groupPassword) {
        // CHECK: send request to join a group
        MessageFromApp message = new MessageFromApp();
        String username = Main.getContext().currentUserName;
        message.from = username;
        message.messageType = "joinGroupResponse";
        message.task = "joinGroup";
        message.toController = "Group";
        message.toGroup = "";
        message.serializedArguments =
                "{\"groupName\":\"" + groupName + "\",\"password\":\""
                        + groupPassword + "\",\"userName\":\"" + username
                        + "\"}";
        Main.getConnection().sendMessage(message);

    }

    private void processChangeGroupPinResponse(MessageFromServer message,
            AppContext ctx) {
        ChangeGroupPinResponse response = new ChangeGroupPinResponse();
        if(ctx.activeScreen != ActiveScreens.grouppaScreen || !(ctx.currentGrouppaFragment instanceof GroupInfo))
            return;
        GroupInfo groupInfo = (GroupInfo) ctx.currentGrouppaFragment;
        try {
            JSONObject args = new JSONObject(message.serializedArguments);
            response.succeeded = args.getBoolean("succeeded");
            response.errorReason = args.getString("errorReason");
            response.newPin = args.getString("newPin");
            if(response.succeeded)
                ctx.joinedGroups.get(ctx.getCurrentGroup()).pin = response.newPin;
            groupInfo.onPinChanged(response);
        } catch (Exception ex) {
            ctx.grouppaActivity.errorPopup("Error: " + ex.getMessage());
        }
    }

    public class ChangeGroupPinResponse {
        public String newPin;
        public boolean succeeded;
        public String errorReason;
    }
    public class JoinGroupResponse {

        public String pin;
        public String groupName;
        public boolean joined;
        public String errorReason;
    }
    public class GetAllMembersResponse {
        public String groupName;
        public GroupMember[] members;
    }
    @Override
    public void reset() {
        // TODO Auto-generated method stub
        
    }
}
